<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TEST</title>
</head>

<body>
    <script>
        // 用一个全局变量存储被注册的副作用函数
        let activeEffect

        // 2. 第二步执行effectFn。
        function effect(fn) {
            // 当effectFn执行时，将其设置为当前激活的副作用函数
            activeEffect = effectFn
            fn()
        }

        // 存储副作用函数
        const bucket = new WeakMap()
        // 原始数据
        const data = { text: 'hello', name: 'zzd', age: 18 }
        // 3. 第三步，对原始数据的代理，触发副作用函数会触发代理对象的get、set。
        const obj = new Proxy(data, {
            get(target, key, receiver) {
                track(target, key)
                return target[key]
            },
            set(target, key, newVal, receiver) {
                target[key] = newVal
                trigger(target, key)
            },
        })
        // 4. 第四步，get中收集依赖，set中改变数据并重新执行属性对应的副作用函数
        function track(target, key) {
            // 没有activeEffect直接return
            if (!activeEffect) return target[key]
            // 根据target从WeakMap中取得depsMap，他也是一个Map类型
            let depsMap = bucket.get(target)
            // 如果不存在depsMap，那么新建一个Map并与target关联
            if (!depsMap) {
                bucket.set(target, (depsMap = new Map()))
            }
            // 再根据key从depsMap中取得deps，它是一个Set类型
            // 里面存储着所有与当前key关联的副作用函数：effects
            let deps = depsMap.get(key)
            // 如果deps不存在，同样新建一个set并与key关联
            if (!deps) {
                depsMap.set(key, (deps = new Set()))
            }
            // 最后将当前激活的副作用函数放入deps
            deps.add(activeEffect)
        }
        function trigger(target, key) {
            //根据target从bucket中取得depsMap，它是key-->effects
            const depsMap = bucket.get(target)
            if (!depsMap) return
            //根据key取得所有副作用函数effects
            const effects = depsMap.get(key)
            //执行副作用函数
            effects && effects.forEach(fn => fn())
        }

        // 1. 第一步调用effect()，传入副作用函数。
        effect(() => {
            let a = obj.text,
                b = obj.name,
                c = obj.age
            console.log('副作用函数执行了')
        })
        setTimeout(() => {
            obj.text = 'dsg'
            obj.name = 'zzd2'
            obj.age = 20
        }, 1000)


        console.log(new Array(6));
    </script>
</body>

</html>